package cn.bonoon.kernel.descriptors.impl;

import java.lang.reflect.Field;

import javax.persistence.Embedded;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import cn.bonoon.kernel.descriptors.DescriptorFactory;
import cn.bonoon.kernel.descriptors.EntityDescriptor;
import cn.bonoon.kernel.descriptors.EntityPropertyAccessor;
import cn.bonoon.kernel.support.entities.AbstractEntity;
import cn.bonoon.kernel.support.entities.EntityDeletable;
import cn.bonoon.kernel.support.entities.EntityMovable;
import cn.bonoon.kernel.support.entities.EntityRecyclable;
import cn.bonoon.kernel.support.entities.EntityScopable;
import cn.bonoon.kernel.support.entities.EntityStatus;
import cn.bonoon.kernel.support.entities.EntityTree;

/**
 * <pre>
 * 描述一个数据库实体；
 * 包括对
 * </pre>
 * @author jackson
 *
 */
public class EntityDescriptorImpl extends AbstractClassDescriptor<EntityPropertyAccessor> implements EntityDescriptor{
	
	private final int model;
	protected class DescriptorInternalVisitor{
		protected void put(String name, EntityPropertyAccessor epa) {
			properties.put(name, epa);
		}
	}
	
	@Override
	public EntityDescriptor initDescriptor() {
		super.initDescriptor();
		return this;
	}
	
	public EntityPropertyAccessor findProperty(String mappedName){
		EntityPropertyAccessor epa = properties.get(mappedName);
		if(null == epa){
			String[] names = mappedName.split("\\.");
			if(names.length > 1){
				String mn = names[0];
				EntityDescriptor temp = this;
				EntityPropertyAccessor pre = temp.get(mn);
				for(int i = 1; null != pre && i < names.length; i++){
					mn += '.' + names[i];
					epa = temp.get(mn);
					if(null == epa){
						temp = DescriptorFactory.entityDescriptor(pre.getType());
						mn = names[i];
						epa = temp.get(mn);
					}
					pre = epa;
				}
			}
		}
		
		return epa;
	}
	
	@Override
	protected AbstractEntityPropertyAccessor parseProperty(Field field) {
		String name = field.getName();
		/*
		 * 有几种需要处理的：
		 * 1.onetomany
		 * 2.manytoone
		 * 3.manytomany
		 * 4.onetoone
		 * 5.embedded
		 */
		if(field.isAnnotationPresent(Embedded.class)){
			return new EmbeddedPropertyAccessorImpl(new DescriptorInternalVisitor(), clazz, name, field);
		} else if(field.isAnnotationPresent(ManyToOne.class)){
			return new OnePropertyAccessorImpl(clazz, name, field, null, null);
		}else{
			OneToOne oto = field.getAnnotation(OneToOne.class);
			if(null != oto){
				return new OnePropertyAccessorImpl(clazz, name, field, null, oto.mappedBy());
			}
			ManyToMany mtm = field.getAnnotation(ManyToMany.class);
			if(null != mtm){
				return new ManyPropertyAccessorImpl(clazz, name, field, null, mtm.mappedBy());
			}
			OneToMany otm = field.getAnnotation(OneToMany.class);
			if(null != otm){
				return new ManyPropertyAccessorImpl(clazz, name, field, null, otm.mappedBy());
			}
		}
		return new EntityPropertyAccessorImpl(clazz, name, field, null);
	}
	
	public int code(){
		return clazz.hashCode();
	}
	
	public EntityDescriptorImpl(Class<?> entityClass){
		super(entityClass);
		int model = 0;
		if(AbstractEntity.class.isAssignableFrom(clazz)){
			model |= BASE;
		}
		if(EntityTree.class.isAssignableFrom(clazz)){
			model |= TREE;
		}
		if(EntityMovable.class.isAssignableFrom(clazz)){
			model |= MOVABLE;
		}
		if(EntityDeletable.class.isAssignableFrom(clazz)){
			model |= DELETABLE;
		}
		if(EntityRecyclable.class.isAssignableFrom(clazz)){
			model |= RECYCLABE;
		}
		if(EntityStatus.class.isAssignableFrom(clazz)){
			model |= STATUS;
		}
		if(EntityScopable.class.isAssignableFrom(clazz)){
			model |= SCOPABLE;
		}
//		if(EntityOwner.class.isAssignableFrom(clazz)){
//			model |= OWNER;
//		}
		this.model = model;
	}
	
	@Override
	public boolean is(int md) {
		return (model & md) == md;
	}

	public boolean hasProperty(String name) {
		return properties.containsKey(name);
	}
}
